﻿// ----------------------------------------------------------------------
// <author name="Moses Kehengu"/>
// <copyright file="Login.cs" company="Futures Group International">
//     Copyright statement. All right reserved
// </copyright>
//
// ------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using GenericTools;
using System.Threading;
using System.Data.Common;
using System.Data.SqlClient;
using DataModels.Enumerations;
using DataModels.Common;
using ReportingManagement.Components;
using System.Windows.Interop;
using DataModels.Models;
using ReportingManagement.Components.Queries;

namespace ReportingManagement
{
    /// <summary>
    /// Login Form
    /// </summary>
    public partial class Login : Form
    {
        #region Class Constants
        const double DEFAULT_OPACITY = 0.90;
        private const string LOCAL_WEB_SERVICES_ADDRESS = "http://localhost:2014/IQService.asmx";
        #endregion

        #region Class Variables
        private UserInformation userInformation;
        private bool dataCached;

        private bool btnLoginEnabled;
        private bool btnDownLoadEnabled;
        private bool btnRecoverPasswordEnabled;
        private bool chkOfflineDataEnabled;
        #endregion

        #region Constructors
        public Login()
        {
            InitializeComponent();
            this.userInformation = null;
            this.dataCached = false;

            AppConfiguration.CacheDBConnectionString = AppConfiguration.SQLCacheDBConnection.Replace("master", AppConfiguration.CacheDBName);   // we don't use MS Access anymore
            AppConfiguration.CacheDBProviderName = AppConfiguration.DBProviderName;
            chkOfflineData_CheckedChanged(null, null);

            // Determing the last creation of offline data
            var backWorker = new BackgroundWorker();
            backWorker.DoWork += new DoWorkEventHandler(backWorker_DoWork);
            backWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backWorker_RunWorkerCompleted);
            backWorker.RunWorkerAsync();

            if (AppConfiguration.AccessMethod == DataAccessMethod.DIRECT_ACCESS)
            {
                chbCacheSessionData.Enabled = false;
                chbCacheSessionData.Checked = false;
                
                chkOfflineData.Enabled = false;
                chkOfflineData.Checked = false;
            }

            if (AppConfiguration.IsRunningDemo) this.Text = this.Text + " :: Running DEMO";

        }

        void backWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            AppConfiguration.EnableErrorLogMail = true;
            if (e.Error == null)
            {
                var dates = e.Result as List<DateTime?>;
                DateTime? cacheCreationDate = dates[0];
                DateTime? cacheDBCutOffPoint = dates[1];

                if (cacheCreationDate == null) rdoLastUpdateDate.Text = "Last update date - [Not Available]";
                else
                {                    
                    rdoLastUpdateDate.Text = String.Format("Last updated on {0}",
                       cacheCreationDate.Value.ToLongDateString());

                    if (cacheDBCutOffPoint.HasValue)
                    {
                        TimeSpan timeSpan = DateTime.Now - cacheDBCutOffPoint.Value;
                        int months = (int)(timeSpan.TotalDays / 30);
                        string label = string.Format("{0} (Starting from {1} months ago)",
                            rdoLastUpdateDate.Text, months);
                        rdoLastUpdateDate.Text = label;
                    }
                }
            }
            else
            {
                rdoLastUpdateDate.Text = "Last update date - [Not Available]";
            }
        }

        void backWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            AppConfiguration.EnableErrorLogMail = false;
            DateTime? cacheCreationDate = Utilities.GetOfflineDataDate();
            DateTime? cacheDBCutOffPoint = Utilities.GetOfflineDataCutOffPoint();

            var dates = new List<DateTime?>();
            dates.Add(cacheCreationDate);
            dates.Add(cacheDBCutOffPoint);
            e.Result = dates;
        }
        #endregion

        #region Event Handlers
        private void btnLogin_Click(object sender, EventArgs e)
        {
            #region Offline Login
            if (chkOfflineData.Checked)
            {
                AppConfiguration.UseOfflineData = true;
                if (AppConfiguration.CacheDBType == CacheDB.MS_ACCESS)
                {
                    AppConfiguration.AccessMethod = DataAccessMethod.OFFLINE_DATA_ACCESS;
                }
                else
                {
                    AppConfiguration.AccessMethod = DataAccessMethod.OFFLINE_DIRECT_ACCESS;
                    string cacheDBConnection = AppConfiguration.SQLCacheDBConnection.Replace("master", AppConfiguration.CacheDBName);
                    AppConfiguration.DBConnectionString = cacheDBConnection;
                    DbCommand command = GenericDataAccess.CreateCommand();
                    try
                    {
                        command.Connection.Open();
                        command.Connection.Close();
                    }
                    catch
                    {
                        DialogResult response = MessageBox.Show(this,
                            String.Format("Could not find the cache database!{0}{0}{1} " +
                                "will try to recreate it. This may take several minutes. Do you want to continue?",
                                Environment.NewLine, AppConfiguration.ApplicationName),
                            AppConfiguration.ApplicationName, MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                        if (response == System.Windows.Forms.DialogResult.Yes)
                        {
                            try
                            {
                                bool okToContinue = DownloadingData.LoadingDBIntoSQLServer(this);
                                if (okToContinue)
                                {
                                    MessageBox.Show(this,
                                        "Cache database has been created successfully. You can now continue.",
                                        AppConfiguration.ApplicationName,
                                        MessageBoxButtons.OK, MessageBoxIcon.Information);

                                    DateTime? cacheCreationDate = Utilities.GetOfflineDataDate();
                                    if (cacheCreationDate == null) rdoLastUpdateDate.Text = "Last update date - [Not Available]";
                                    else rdoLastUpdateDate.Text = String.Format("Last updated on {0}",
                                        cacheCreationDate.Value.ToLongDateString());
                                }
                                else
                                {
                                    MessageBox.Show(this,
                                        "Cache database could not be created. Check your settings for local cache database.",
                                        AppConfiguration.ApplicationName,
                                        MessageBoxButtons.OK, MessageBoxIcon.Hand);
                                }
                            }
                            catch (Exception ex)
                            {
                                MessageBox.Show(this, ex.Message, "Error during creating cache database",
                                    MessageBoxButtons.OK, MessageBoxIcon.Error);
                            }
                        }
                        else return;
                    }
                }
            }
            #endregion
            else
            {
                AppConfiguration.UseOfflineData = false;
                if (AppConfiguration.AccessMethod != DataAccessMethod.DIRECT_ACCESS)
                {
                    AppConfiguration.AccessMethod = DataAccessMethod.WEB_SERVICES;
                    string cacheDBConnection = AppConfiguration.SQLCacheDBConnection.Replace("master", AppConfiguration.CacheDBName);
                    AppConfiguration.DBConnectionString = cacheDBConnection;
                }
            }

            btnLogin.Enabled = false;
            Application.DoEvents();
            if (String.IsNullOrEmpty(txtUsername.Text) || String.IsNullOrEmpty(txtPassword.Text))
            {
                MessageBox.Show(this, "Please provide your username and password",
                    String.Format("{0} Login", AppConfiguration.ApplicationName), 
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                if (String.IsNullOrEmpty(txtUsername.Text)) txtUsername.Focus();
                else txtPassword.Focus();
                btnLogin.Enabled = true;
                return;
            }
            try
            {
                string username = txtUsername.Text;
                string password = txtPassword.Text;
                /* We don't need to encrypt, already taken care someplace else
                if ((AppConfiguration.AccessMethod == DataAccessMethod.OFFLINE_DATA_ACCESS) ||
                    (AppConfiguration.AccessMethod == DataAccessMethod.OFFLINE_DIRECT_ACCESS))
                {
                    password = DataTransformation.Encrypt(password);
                }
                */

                Cursor.Current = Cursors.WaitCursor;                
                UserInformation userInfo = UserInformation.CreateUser(username, password);
                Cursor.Current = Cursors.Default;
                if (userInfo != null)
                {
                    this.userInformation = userInfo;
                    this.dataCached = chbCacheSessionData.Checked;
                    this.DialogResult = System.Windows.Forms.DialogResult.OK;
                    this.Close();
                    return;
                }
                else
                {
                    MessageBox.Show(this, "Invalid username and/or password", AppConfiguration.ApplicationName,
                        MessageBoxButtons.OK, MessageBoxIcon.Stop);
                    btnLogin.Enabled = true;
                    return;
                }
            }
            
            #region Handling Exceptions
            catch (System.Net.WebException ex)
            {
                string message = ex.Message + "\n\n"
                    + "The server may be very busy ,please try again little bit later or\n"
                    + "Make sure you have very good internet connection";
                MessageBox.Show(this, message, AppConfiguration.ApplicationName,
                    MessageBoxButtons.OK, MessageBoxIcon.Stop);
                return;
            }
            catch (InvalidOperationException ex)
            {
                int index = ex.Message.IndexOf("<!DOCTYPE");
                if (index != -1)
                {
                    string webContents = ex.Message.Substring(index);
                    var webError = new WebBasedErrorDisplay(webContents);
                    WindowInteropHelper helper = new WindowInteropHelper(webError);
                    helper.Owner = this.Handle;
                    webError.ShowDialog();
                    return;
                }
            }
            catch (Exception ex)
            {
                Cursor.Current = Cursors.Default;
                MessageBox.Show(this,
                    String.Format("The followong error occured.{0}{0}{1}", Environment.NewLine, ex.Message),
                    AppConfiguration.ApplicationName,
                    MessageBoxButtons.OK, MessageBoxIcon.Stop);
                return;
            }
            #endregion
            
            finally
            {
                btnLogin.Enabled = true;
            }
        }

        private void btnRecoverPassword_Click(object sender, EventArgs e)
        {
            if (String.IsNullOrEmpty(txtUsername.Text))
            {
                MessageBox.Show(this, "Please provide your username so that your password can be recovered",
                    "Password Recovery Utility", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txtUsername.Focus();
                return;
            }

            string username = txtUsername.Text;
            try
            {
                btnRecoverPassword.Enabled = false;
                Application.DoEvents();
                Cursor.Current = Cursors.WaitCursor;
                UserInformation userInfo = UserInformation.CreateUser(username);
                Cursor.Current = Cursors.Default;
                if (userInfo != null)
                {
                    string email = userInfo.EmailAddress;
                    string password = userInfo.Password;

                    string subject = String.Format("{0} Password Recovery", AppConfiguration.ApplicationName);
                    string body = String.Format(@"Your {0} password is <span style=""font-weight:bold;"">{1}</span>", AppConfiguration.ApplicationName, password);
                    
                    Cursor.Current = Cursors.WaitCursor;
                    Utilities.SendMailSync(email, subject, body);
                    Cursor.Current = Cursors.Default;
                    
                    //Thread.Sleep(3000); //buy some time for sending e-mail
                    MessageBox.Show(this, "Your password has been sent to your e-mail account.",
                        "Password Recovery Utility", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    btnRecoverPassword.Enabled = true;
                    return;
                }
                else
                {
                    MessageBox.Show(this,
                        String.Format("You are not registered in {0}.\nPlease contact your system administrator for further assistance.",
                            AppConfiguration.ApplicationName),
                        "Password Recovery Utility", MessageBoxButtons.OK, MessageBoxIcon.Stop);
                    btnRecoverPassword.Enabled = true;
                    return;
                }
            }
            catch
            {
                Cursor.Current = Cursors.Default;
                MessageBox.Show(this, "Please make sure you have internet connection", "Password Recovery Utility", 
                    MessageBoxButtons.OK, MessageBoxIcon.Stop);
                btnRecoverPassword.Enabled = true;
            }
        }

        private void btnAboutIQSMS_Click(object sender, EventArgs e)
        {
#if DEBUG
            DataTable dataTable = new DataTable();
            DataColumn column = new DataColumn("Name", Type.GetType("System.String"));
            dataTable.Columns.Add(column); 
            column = new DataColumn("Name Tag", Type.GetType("System.String"));
            dataTable.Columns.Add(column);

            DataRow row = dataTable.NewRow();
            row[0] = "And he said unto me, My grace is sufficient for thee: for my strength is made perfect in weakness";
            row[1] = "September";
            dataTable.Rows.Add(row);
            row = dataTable.NewRow();
            row[0] = "December";
            dataTable.Rows.Add(row);
            row = dataTable.NewRow();
            row[0] = "November";
            row[1] = "Just some tag";
            dataTable.Rows.Add(row);
            dataTable.TableName = "Q4 Months";

            var exporter = new GenericTools.DataExporting.ExcelFileExporting(dataTable);
            string outputFile = exporter.Export();
            System.IO.File.Copy(outputFile, @"c:\IQSMS\demoExport.xlsx", true);
            
            var parameters = new List<QueryParameter>
            {
                new QueryParameter
                {
                    Name = "End Month",
                    Description = "End of the month",
                    ValidationExpression = "^0?[1-9]{1}[0-2]{0,1}$",
                },
                new QueryParameter
                {
                    Name = "End Year",
                    Description = "End of the year",
                    ValidationExpression = "^20[0-1][0-9]$"
                }
            };

            QueryParametersCreator creator = new QueryParametersCreator(parameters);
            var helper = new WindowInteropHelper(creator);
            helper.Owner = this.Handle;

            bool? okToContinue = creator.ShowDialog();
            if (okToContinue.HasValue && okToContinue.Value)
            {
                //var results = collector.ParameterValues;
            }

            ReportParameterCollector collector = new ReportParameterCollector(parameters);
            helper = new WindowInteropHelper(collector);
            helper.Owner = this.Handle;
            
            okToContinue = collector.ShowDialog();
            if (okToContinue.HasValue && okToContinue.Value)
            {
                var results = collector.ParameterValues;
            }
#else
            AboutIQSMS about = new AboutIQSMS();
            about.ShowDialog(this);
#endif
        }

        private void chkOfflineData_CheckedChanged(object sender, EventArgs e)
        {
            rdoDownloadLatestData.Enabled = chkOfflineData.Checked;
            rdoLastUpdateDate.Enabled = chkOfflineData.Checked;
            if (chkOfflineData.Checked)
            {
                //chbCacheSessionData.Enabled = false;
                chbCacheSessionData.Checked = false;
                AppConfiguration.AccessMethod = DataAccessMethod.OFFLINE_DIRECT_ACCESS;
            }
            else
            {
                //chbCacheSessionData.Enabled = true;
                if (AppConfiguration.AccessMethod != DataAccessMethod.DIRECT_ACCESS) 
                    AppConfiguration.AccessMethod = DataAccessMethod.WEB_SERVICES;
            }
        }

        private void btnDownload_Click(object sender, EventArgs e)
        {
            var cutOffPointEditor = new OfflineDataCutOffPoint();
            WindowInteropHelper helper = new WindowInteropHelper(cutOffPointEditor);
            helper.Owner = this.Handle;
            bool? okToContinue = cutOffPointEditor.ShowDialog();
            
            DateTime cutOffPoint;
            if (okToContinue.HasValue)
            {
                if (okToContinue.Value) cutOffPoint = cutOffPointEditor.CutOffPoint;
                else return;
            }
            else return;

            btnDownload.Enabled = false;
            Application.DoEvents();

            DownloadingData downloading = new DownloadingData(false, cutOffPoint);
            DialogResult response = downloading.ShowDialog(this);
            if (response == System.Windows.Forms.DialogResult.OK)
            {
                rdoLastUpdateDate.Checked = true;
                // Determing the last creation of offline data
                DateTime? cacheCreationDate = Utilities.GetOfflineDataDate();
                DateTime? cacheDBCutOffPoint = Utilities.GetOfflineDataCutOffPoint();
                if (cacheCreationDate == null) rdoLastUpdateDate.Text = "Last update date - [Not Available]";
                else
                {
                    rdoLastUpdateDate.Text = String.Format("Last updated on {0}",
                       cacheCreationDate.Value.ToLongDateString());
                    if (cacheDBCutOffPoint != null)
                    {
                        TimeSpan timeSpan = DateTime.Now - cacheDBCutOffPoint.Value;
                        int months = (int)(timeSpan.TotalDays / 30);
                        string label = string.Format("{0} (Starting from {1} months ago)", 
                            rdoLastUpdateDate.Text, months);
                        rdoLastUpdateDate.Text = label;
                    }
                }
            }
            else btnDownload.Enabled = true;
        }

        private void rdoDownloadLatestData_CheckedChanged(object sender, EventArgs e)
        {
            btnDownload.Enabled = rdoDownloadLatestData.Checked;
        }

        private void rdoDownloadLatestData_EnabledChanged(object sender, EventArgs e)
        {
            if (rdoDownloadLatestData.Enabled)
            {
                if (rdoDownloadLatestData.Checked) btnDownload.Enabled = true;
                else btnDownload.Enabled = false;
            }
            else
            {
                btnDownload.Enabled = false;
            }
        }

        private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            btnLogin.Enabled = btnLoginEnabled;
            btnDownload.Enabled = btnDownLoadEnabled;
            btnRecoverPassword.Enabled = btnRecoverPasswordEnabled;
            chkOfflineData.Enabled = chkOfflineDataEnabled;
            if (AppConfiguration.AddressFound) Opacity = 1.00;
            else Opacity = 0.85; // A little bit to the failure in retrieving the address
        }

        private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
#if DEBUG
            // During debugging we don't use online address, just the one in the config file
            //System.Threading.Thread.Sleep(2000);
            Utilities.WebServicesURL = LOCAL_WEB_SERVICES_ADDRESS;
#else
            if (AppConfiguration.AddressFound) return;
            else
            {
                AppConfiguration.DetermineWebserviceAddress();
                if (AppConfiguration.AddressFound) Utilities.WebServicesURL = AppConfiguration.WebServiceURL;
            }
#endif            
        }

        private void Login_Shown(object sender, EventArgs e)
        {
            btnLoginEnabled = btnLogin.Enabled;
            btnDownLoadEnabled = btnDownload.Enabled;
            btnRecoverPasswordEnabled = btnRecoverPassword.Enabled;
            chkOfflineDataEnabled = chkOfflineData.Enabled;

            btnLogin.Enabled = false;
            btnDownload.Enabled = false;
            btnRecoverPassword.Enabled = false;
            chkOfflineData.Enabled = false;
            Opacity = DEFAULT_OPACITY;

            backgroundWorker.RunWorkerAsync();
        }

        private void Login_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (backgroundWorker.IsBusy) backgroundWorker.CancelAsync();
            else backgroundWorker.Dispose();
        }
        #endregion

        #region Public Properties
        public UserInformation AuthenticatedUser
        {
            get
            {
                return this.userInformation;
            }
        }

        /// <summary>
        /// Checks whether session data should be cached or not
        /// </summary>
        public bool DataCached
        {
            get
            {
                return this.dataCached;
            }
        }
        #endregion                

        /*
        private void button1_Click(object sender, EventArgs e)
        {
            string connectionString = @"Data Source=(local)\SQL2008R2;Initial Catalog=IQSMS_TestDB;User ID=sa;Password=c0nstella;";
            SqlConnection connection = new SqlConnection(connectionString);
            connection.Open();
            SqlCommand command = connection.CreateCommand();
            DbParameter param = null;

            command.CommandText = "SELECT ID, Password FROM Users";
            DataTable usersDataTable = GenericDataAccess.ExecuteSelectCommand(command, false);

            foreach (DataRow row in usersDataTable.Rows)
            {
                string id = row["ID"].ToString();
                string password = row["Password"].ToString();
                string encryptedPassword = DataTransformation.Encrypt(password);
                command.CommandText = @"UPDATE Users SET [Password]=@Password WHERE ID=@ID";
                command.Parameters.Clear();

                param = command.CreateParameter();
                param.ParameterName = "@Password";
                param.DbType = DbType.String;
                param.Value = encryptedPassword;
                command.Parameters.Add(param);

                param = command.CreateParameter();
                param.ParameterName = "@ID";
                param.DbType = DbType.Int32;
                param.Value = id;
                command.Parameters.Add(param);
                command.ExecuteNonQuery();
            }
            connection.Close();
        }
        */
    }
}
